package com.zhenyi.core.wechatPay;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;

import com.jfinal.kit.JsonKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.weixin.sdk.kit.PaymentKit;
import com.utils.HttpUtils;
import com.utils.PathUtils;
import com.wxpay.utils.MD5;
import com.wxpay.utils.MD5Util;
import com.wxpay.utils.XmlUtil;

public class PayUtils {
	public String appid = "";
	public String partner = "1494469742";
	public String partnerkey = "";
	private String charset = "utf-8";
	private static final String URL_REFUND = "https://api.mch.weixin.qq.com/secapi/pay/refund";
	private static final String URL_REVERSE = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
	/**
	 * p12证书路径 D://xxx.p12
	 */
	private String sslPath;

	public PayUtils(String appid, String partner, String partnerkey, String sslPath) {
		this.appid = appid;
		this.partner = partner;
		this.partnerkey = partnerkey;
		this.sslPath = sslPath;
	}

	public static PayUtils instance() {
		String path = PathUtils.getFile("wechatssl", "cert", "apiclient_cert.p12");
		return new PayUtils("wx6d47db34d18f5e3a", "1494469742", "zhenyikejizhenyikejizhenyikejizy", path);
	}

	/**
	 * 元转换成分
	 * 
	 * @param money
	 * @return
	 */
	public static String getMoney(String amount) {
		if (amount == null) {
			return "";
		}
		// 金额转化为分为单位
		String currency = amount.replaceAll("\\$|\\￥|\\,", ""); // 处理包含, ￥
																// 或者$的金额
		int index = currency.indexOf(".");
		int length = currency.length();
		Long amLong = 0l;
		if (index == -1) {
			amLong = Long.valueOf(currency + "00");
		} else if (length - index >= 3) {
			amLong = Long.valueOf((currency.substring(0, index + 3)).replace(".", ""));
		} else if (length - index == 2) {
			amLong = Long.valueOf((currency.substring(0, index + 2)).replace(".", "") + 0);
		} else {
			amLong = Long.valueOf((currency.substring(0, index + 1)).replace(".", "") + "00");
		}
		return amLong.toString();
	}

	/**
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 */
	public String createSign(Map<String, String> packageParams) {
		StringBuffer sb = new StringBuffer();
		Set<?> es = packageParams.entrySet();
		Iterator<?> it = es.iterator();
		while (it.hasNext()) {
			@SuppressWarnings("rawtypes")
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			if (k.endsWith(XmlUtil.FLAG_DATA)) {
				k = k.replace(XmlUtil.FLAG_DATA, "");
			}
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + partnerkey);
		String sign = MD5Util.MD5Encode(sb.toString(), this.charset).toUpperCase();
		return sign;

	}

	public Map<?, ?> refundOrderNo(String orderNo, String totalFee, String refundFee, String refundNo) {
		return refundOrderNo(orderNo, totalFee, refundFee, refundNo, null);
	}

	/**
	 * 撤单
	 * https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
	 * 
	 * @param orderNo
	 * @return
	 */
	public Map<String, String> reverse(String orderNo) {
		String appId = this.appid;
		// totalFee = getMoney(totalFee);
		// refundFee = getMoney(refundFee);
		/**
		 * 商户号 微信支付分配的商户号
		 */
		String mch_id = partner;
		/**
		 * 随机字符串
		 */
		String nonce_str = getNonceStr();
		/**
		 * 微信订单号 微信生成的订单号，在支付通知中有返回
		 */
		// String transaction_id = transactionId;
		/**
		 * 操作员 操作员帐号, 默认为商户号
		 */
		String op_user_id = partner;

		Map<String, String> map = new TreeMap<String, String>();
		map.put("appid", appId);
		map.put("mch_id", mch_id);
		map.put("nonce_str", nonce_str);
		// transaction_id,out_trade_no 二选一
		// map.put("transaction_id", transaction_id);
		map.put("out_trade_no", orderNo);
		map.put("op_user_id", op_user_id);

		if (PropKit.getBoolean("devMode", false)) {
			System.out.println(JsonKit.toJson(map));
			System.err.println(sslPath);
		}
		String sign = createSign(map);
		String xml = genXML(map, sign);
		try {
			String response = HttpUtils.postSSL(URL_REVERSE, xml, sslPath, partner);
			// System.out.println(sslPath);
			Map<String, String> result = XmlUtil.parseToMap(response);
			if (!isXMLSuccess(result)) {
				return null;
			}
			if (!checkSign(result)) {
				return null;
			}
			return result;
		} catch (KeyManagementException | UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException
				| CertificateException | IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;

	}

	public Map<String, String> refundOrderNo(String orderNo, String totalFee, String refundFee, String refundNo,
			String notify_url) {
		String appId = this.appid;
		// totalFee = getMoney(totalFee);
		// refundFee = getMoney(refundFee);
		/**
		 * 商户号 微信支付分配的商户号
		 */
		String mch_id = partner;
		/**
		 * 随机字符串
		 */
		String nonce_str = getNonceStr();
		/**
		 * 微信订单号 微信生成的订单号，在支付通知中有返回
		 */
		// String transaction_id = transactionId;
		/**
		 * 商户退款单号 商户系统内部的退款单号，商户系统内部唯一，同一退款单号多次请求只退一笔
		 */
		String out_refund_no = refundNo;
		/**
		 * 总金额
		 */
		String total_fee = totalFee;
		/**
		 * 退款金额
		 */
		String refund_fee = refundFee;
		/**
		 * 操作员 操作员帐号, 默认为商户号
		 */
		String op_user_id = partner;

		Map<String, String> map = new TreeMap<String, String>();
		map.put("appid", appId);
		map.put("mch_id", mch_id);
		map.put("nonce_str", nonce_str);
		// transaction_id,out_trade_no 二选一
		// map.put("transaction_id", transaction_id);
		map.put("out_trade_no", orderNo);
		map.put("out_refund_no", out_refund_no);
		map.put("total_fee", total_fee);
		map.put("refund_fee", refund_fee);
		map.put("op_user_id", op_user_id);
		if (StrKit.notBlank(notify_url)) {
			map.put("notify_url", notify_url);
		}

		boolean devMode = PropKit.getBoolean("devMode", false);

		if (devMode) {
			System.out.println(JsonKit.toJson(map));
			System.err.println(sslPath);
		}
		String sign = createSign(map);
		String xml = genXML(map, sign);
		try {
			String response = HttpUtils.postSSL(URL_REFUND, xml, sslPath, partner);
			// System.out.println(sslPath);
			Map<String, String> result = XmlUtil.parseToMap(response);
			// String mySign = PaymentKit.createSign(refund, PARTNER_KEY);
			// if (!mySign.equals(sign)) {
			// LogKit.warn("sign error eee");
			// System.err.println(sign);
			// System.err.println(mySign);
			// return refund;
			// }
			if (!checkSign(result)) {
				if (devMode) {
					System.out.println("!checkSign");
					System.out.println(response);
				}
				return null;
			}
			if (!isXMLSuccess(result)) {
				// if (devMode) {
				// System.out.println("!isXMLSuccess");
				// }
				return result;
			}
			return result;
		} catch (KeyManagementException | UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException
				| CertificateException | IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("exception");
		return null;
	}

	/**
	 * 生成xml里面的节点
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	private String genKV(String key, String value) {
		String txt = "<KEY>VALUE</KEY>";
		txt = txt.replace("KEY", key);
		txt = txt.replace("VALUE", value);
		return txt;
	}

	/**
	 * 获取随机字符串
	 * 
	 * @return
	 */
	public static String getNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}

	/**
	 * 生成xml,并添加sign
	 * 
	 * @param map
	 * @param sign
	 * @return
	 */
	private String genXML(Map<String, String> map, String sign) {
		Set<String> sets = map.keySet();
		String xml = "<xml>";
		for (String key : sets) {
			String value = map.get(key);
			xml = xml + genKV(key, value);
		}
		xml = xml + genKV("sign", sign);
		xml = xml + "</xml>";
		return xml;
	}

	private static final String SUCCESS = "SUCCESS";

	private boolean checkSign(Map<String, String> result) {
		String sign = result.get("sign");
		String mySign = PaymentKit.createSign(result, partnerkey);
		if (!mySign.equals(sign)) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 检测return_code是否返回SUCCESS
	 * 
	 * @param xml
	 * @return
	 */
	public static boolean isXMLSuccess(Map<?, ?> xml) {
		if (xml == null) {
			return false;
		}
		try {
			String return_code = (String) xml.get("return_code");
			String result_code = (String) xml.get("result_code");
			return return_code.equals(SUCCESS) && result_code.equals(SUCCESS);
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 检测return_code是否返回SUCCESS
	 * 
	 * @param xml
	 * @return
	 */
	public static boolean isXMLSuccess(String xml) {
		Map<?, ?> result = XmlUtil.parseToMap(xml);
		return isXMLSuccess(result);
	}
}
